// (C) 2022 Intel Corporation. All rights reserved.
// Your use of Intel Corporation's design tools, logic functions and other 
// software and tools, and its AMPP partner logic functions, and any output 
// files from any of the foregoing (including device programming or simulation 
// files), and any associated documentation or information are expressly subject 
// to the terms and conditions of the Intel Program License Subscription 
// Agreement, Intel FPGA IP License Agreement, or other applicable 
// license agreement, including, without limitation, that your use is for the 
// sole purpose of programming logic devices manufactured by Intel and sold by 
// Intel or its authorized distributors.  Please refer to the applicable 
// agreement for further details.

`include "mainfpga_version.vh"

module err_det(
   input CATERR_RMCA_N,    // input error signal
   input rst_n,
   input CLK,              //clock frequency = 100MHz
   output reg [1:0] MODE   //MODE  = 00 when no error, 01 when a short duration of error, 10 when a long duration error occurs
);
reg err_r1,err_r2,err_r3;
wire err_fallingedge;

always @(posedge CLK) begin
  err_r1 <= CATERR_RMCA_N;
  err_r2 <= err_r1;
  err_r3 <= err_r2;
  end

assign err_fallingedge = err_r3 && !err_r2;//detect fallingedge of CATERR_RMCA_N



/* -----------------        state machine  ------------------- */
reg [3:0] state;
reg [4:0] cnt;
parameter idle    = 4'b0001;     //idle state, waiting for CATEER_RMCA_N to deassert
parameter count   = 4'b0010;     //count state, count the duration of low level
parameter hold    = 4'b0100;     //hold state, output MODE keep 01 for a specific time(1 ms)
parameter longerr = 4'b1000;     //longerror state, a long error is detected(exceeds 200ns)

reg         wStart1msTimerB;
wire        wDoneTimer1msB;
always @(posedge CLK or negedge rst_n) begin
   if(!rst_n) begin
             state <= idle;
	          cnt   <= 0;
	          end
   else begin
      case(state) 
	  idle:    begin      cnt   <= 0;
            wStart1msTimerB    <= 0; 
	        if(err_fallingedge)
	                 state <= count;
			else     state <= idle;
			     end
    count:   begin       cnt   <= cnt+1;
	         wStart1msTimerB    <= 0; 
            if((!err_r2) && (cnt>=30))    //if err_r2 is at low level and the counter value exceed 28 BCLK (16 BCLK + interconnect loading concern)
				                              //transfer to a long-error state
				      state <= longerr;
				else begin 
				      if(err_r2)             //else, the err_r2 back to high level, indicating the low level duration
						                       //doens't exceed 200ns, then transfer to hold state
				         state <= hold;
				    else state <= count;
					 end
				  end
	  hold:   begin       cnt   <= 0;
	          wStart1msTimerB   <= 1;
	        if(wDoneTimer1msB)  begin       // Hold on for 1ms
			       if(err_r2)                 //if hold for 1ms finished and CATERR_RMCA_N returns to 1
					   state    <= idle;        //then the state transfer to idle, waiting for the next fallingedge
					 else 
					   state    <= count;       //else, CATERR_RMCA_N is still 0, jump to count state directly
					                            //and decide which kind of error is this	
					                end

			  else state    <= hold;
			     end
  longerr:   begin       cnt   <= 0;
             wStart1msTimerB   <= 0;
           if(err_r2)
			       state    <= idle;
			  else state    <= longerr;
			     end
  default:   begin  
          wStart1msTimerB    <= 0; 
						  state    <= idle;
                      cnt    <= 0;
				 end
      endcase
        end
end


/*---------------      delay   part         ---------------*/
`ifdef      SIMULATION
localparam T_1mS_100M   =  18'd50;  //count limit = 50 cycles for simulation scene
`else
localparam T_1mS_100M   =  18'd100000;//count limit = 100000 cycles for actual scene
`endif

delay #(.COUNT(T_1mS_100M)) 
     Timer1msB(
               .iClk(CLK),
               .iRst(rst_n),
               .iStart(wStart1msTimerB),
               .iClrCnt(1'b0),
               .oDone(wDoneTimer1msB)
               );
					

//------------------      output part     ------------------
always @(posedge CLK or negedge rst_n) begin
   if(!rst_n) begin
                 MODE <= 2'b00;
	          end
   else  begin
      case(state) 
	  idle:       MODE <= 2'b00;

    count:       MODE <= 2'b00;
	 
	  hold:       MODE <= 2'b01;
	  
  longerr:       MODE <= 2'b10; 
		
   default:      MODE <= 2'b00;
      endcase
	     end
end

endmodule
